package edu.mse.camel.client.chat.views;

import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.part.ViewPart;

import edu.mse.camel.client.chat.message.IMessage;
import edu.mse.camel.client.chat.message.Message;
import edu.mse.camel.client.chat.message.MessageList;
import edu.mse.camel.client.eventbus.pubsub.EventManager;
import edu.mse.camel.client.eventbus.pubsub.ISubscriber;
import edu.mse.camel.client.events.EventIDs;
import edu.mse.camel.client.events.IEvent;
import edu.mse.camel.client.events.peer.SendChatEvent;
import edu.mse.camel.client.events.server.QuerySessionListEvent;
import edu.mse.camel.client.events.server.QuerySessionListEvent.SessionList;
import edu.mse.camel.client.session.team.ITeamMember;
import edu.mse.camel.client.session.team.TEAMMEMBER_STATUS;
import edu.mse.camel.client.session.team.TeamList;
import edu.mse.camel.client.core.session.event.ClientInternalEvent;

/**
 * This sample class demonstrates how to plug-in a new workbench view. The view
 * shows data obtained from the model. The sample creates a dummy model on the
 * fly, but a real implementation would connect to the model available either in
 * this or another plug-in (e.g. the workspace). The view is connected to the
 * model using a content provider.
 * <p>
 * The view uses a label provider to define how model objects should be
 * presented in the view. Each view can present the same model objects using
 * different labels and icons, if needed. Alternatively, a single label provider
 * can be shared between views in order to ensure that objects of the same type
 * are presented in the same way everywhere.
 * <p>
 */

public class ChatView extends ViewPart implements Observer, ISubscriber {

	private StyledText messageViewer;
	private Table participantViewer;
	private Text inputText;
	private Button sendButton;
	private TableItem item;

	/**
	 * The constructor.
	 */
	public ChatView() {
		MessageList.getInstance().addObserver(this);
		EventManager.getInstance().subscribeTo(EventIDs.CLIENT_INTERNAL_EVENT, this);
	}

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent) {

		GridLayout parentLayout = new GridLayout();
		parentLayout.numColumns = 2;
		parentLayout.makeColumnsEqualWidth = false;
		parent.setLayout(parentLayout);
		parent.setSize(new Point(300, 200));
		
		messageViewer = new StyledText(parent, SWT.V_SCROLL | SWT.MULTI);
		GridData messageViewerData = new GridData();
		messageViewerData.heightHint = 200;
		messageViewerData.horizontalAlignment = GridData.FILL;
		messageViewerData.verticalAlignment = GridData.FILL;
		messageViewerData.grabExcessHorizontalSpace = false;
		messageViewerData.grabExcessVerticalSpace = true;
		messageViewer.setLayoutData(messageViewerData);
		messageViewer.setEditable(false);

		participantViewer = new Table(parent, SWT.V_SCROLL | SWT.BORDER);
		GridData participantViewerData = new GridData();
		participantViewerData.grabExcessVerticalSpace = true;
		participantViewerData.verticalAlignment = GridData.FILL;
		participantViewer.setLayoutData(participantViewerData);
		participantViewer.layout();

		inputText = new Text(parent, SWT.V_SCROLL | SWT.BORDER);
		GridData inputTextData = new GridData();
		inputTextData.horizontalAlignment = GridData.FILL;
		inputTextData.heightHint = 100;
		inputTextData.grabExcessHorizontalSpace = true;
		inputTextData.grabExcessVerticalSpace = true;
		inputText.setLayoutData(inputTextData);
		// inputText.setEnabled(true);
		inputText.addKeyListener(new KeyAdapter() {

			@Override
			public void keyPressed(KeyEvent event) {
				inputTextKeyPressed(event);
			}

		});

		sendButton = new Button(parent, SWT.PUSH | SWT.CENTER);
		GridData sendButtonData = new GridData(SWT.FILL);
		sendButton.setLayoutData(sendButtonData);
		sendButton.setText("Send");
		sendButton.addListener(SWT.Selection, new Listener() {

			@Override
			public void handleEvent(Event event) {
				inputTextButtonPressed(event);
			}
		});

		chatViewEnable();
	}

	private void chatViewEnable() {
		
		if (TeamList.getInstance().getMyStatus().equals(
				TEAMMEMBER_STATUS.SESSION)) {
			inputText.setEnabled(true);
			sendButton.setEnabled(true);
		} else {
			inputText.setEnabled(false);
			sendButton.setEnabled(false);
		}
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {

		inputText.setFocus();
		participantViewer.setFocus();
		IWorkbenchPartSite site = getSite();
		String message = "";
		if (site instanceof IViewSite) {

			if (TeamList.getInstance().getMyStatus().equals(
					TEAMMEMBER_STATUS.SESSION)) {
				message = ChatViewConstants.LOGIN_IN_SESSION_STATUS_MESSAGE
				+ ChatViewConstants.SESSION_ID_MESSAGE_SEPARATOR
				+ getSessionID(TeamList.getInstance().getMe());

			} else {
				message = ChatViewConstants.LOGIN_NOT_IN_SESSION_STATUS_MESSAGE;
			}

			((IViewSite) site).getActionBars().getStatusLineManager()
			.setMessage(message);

		}

	}

	/**
	 * Gets the session information of the participant in session
	 * 
	 * @param teamMember
	 * 		, the team member
	 * @return
	 */
	private String getSessionID(ITeamMember me) {
		QuerySessionListEvent qslEvent = new QuerySessionListEvent();
		EventManager.getInstance().dispatchEventSynchronous(qslEvent, true);
		List<SessionList> sessionList = qslEvent.getSessionList();
		String mySession = "";
		for (SessionList sList : sessionList) {
			List<String> participants = sList.getParticipants();
			if (participants != null) {
				for (String participant : participants) {
					if (participant.equalsIgnoreCase(me.getName())) {
						mySession = sList.getsessionId().toString()
						+ ChatViewConstants.SESSION_ID_TITLE_SEPARATOR
						+ sList.getTitle();
						break;
					}
				}
			}
		}
		return mySession;
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		if(! messageViewer.isDisposed()){
			Display.getDefault().syncExec(new Runnable() {
				@Override
				public void run() {
					if (messageViewer != null) {
						messageViewer.redraw();
						showMessageList();
					}
				}
			});
		}
	}

	public void inputTextKeyPressed(KeyEvent event) {
		if (event.keyCode == 13) {
			messagePublish();
		}
	}

	public void inputTextButtonPressed(Event event) {
		messagePublish();
	}

	public void messagePublish() {
		try {
			String s = inputText.getText().trim();
			if (!s.equals("")) {
				
				Message message = new Message(s, TeamList.getInstance()
						.getMe().getName(), new Date());
				MessageList.getInstance().addMessage(message);
				SendChatEvent sce = new SendChatEvent(s);
				EventManager.getInstance().dispatchEventAsynchronous(sce);
				Display.getDefault().syncExec(new Runnable() {
					@Override
					public void run() {
							showMessageList();
							inputText.setText("");
							inputText.redraw();
							inputText.setFocus();
					}
				});
			}
		} catch (Exception e) {
			System.err.println("Error" + e);
		}
	}

	private void decorateMessage(IMessage message) {
		int startOffset;
		int length;
		String append;
		
		String content = message.getContent().trim();
		
		append = message.getName() + " :" + content + System.getProperty("line.separator");
		startOffset = messageViewer.getText().length();
		length = append.length();

		StyleRange styleRange = new StyleRange();
		styleRange.start = startOffset;
		styleRange.length = length;
		styleRange.foreground = new Color(Display.getDefault(), message.getColor());
		
		messageViewer.append(append);
		messageViewer.setStyleRange(styleRange);
		
	}

	private void showMessageList() {

		List<IMessage> messages = MessageList.getInstance().getMessages();

		messageViewer.setText("");

		for (IMessage message : messages) {
			decorateMessage(message);
		}

		messageViewer.setTopIndex(messageViewer.getLineCount());
	}

	private void showParticipantList() {
		List<ITeamMember> participants = TeamList.getInstance()
		.getSessionTeamMembers();
		participantViewer.clearAll();
		participantViewer.removeAll();
		for (ITeamMember participant : participants) {
			item = new TableItem(participantViewer, SWT.NONE);
			if (!messageViewer.isDisposed()) {
				item.setForeground(new Color(Display.getDefault(), participant.getColor()));
			}
			item.setText(participant.getName());
		}
	}

	@Override
	public void notifyEvent(IEvent e) {

		if(!messageViewer.isDisposed()){
			if(e.getEventID().equalsIgnoreCase(EventIDs.CLIENT_INTERNAL_EVENT)){
				ClientInternalEvent cie = (ClientInternalEvent) e ;
				if (cie.getType() == (ClientInternalEvent.JOIN_SESSION) || 
						cie.getType() == (ClientInternalEvent.CREATE_SESSION)){
					MessageList.getInstance().getMessages().clear();
					Display.getDefault().syncExec(new Runnable() {
						@Override
						public void run() {
							showMessageList();
						}
					});
				}
			}
				
			Display.getDefault().syncExec(new Runnable() {
				@Override
				public void run() {
					if (participantViewer != null) {
						participantViewer.redraw();
						showParticipantList();
						chatViewEnable();
					}
				}
			});
		}
	}

	@Override
	public void dispose() {
		EventManager.getInstance().unSubscribeTo(EventIDs.CLIENT_INTERNAL_EVENT, this);
		super.dispose();
	}
}